/*
 * Copyright (C) 2025 Tsingteng MicroSystem
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "nfa_hci_api.h"
#include "hci_transport.h"
#include "hci_defs.h"
#include "nfa_base.h"
#include "nfc_log_api.h"
#include "nci_feature.h"

/**
 * @brief 处理HCI event(transaction)事件
 */
#if IS_FEATURE_ON(NCI_FEATURE_HCI)
static void hci_event_dispatcher(uint8_t pipe, const uint8_t *data, uint16_t data_len);
static bool find_param_from_bertlv(const uint8_t *data, uint16_t data_len, uint8_t tag, const uint8_t **param_val, uint16_t *param_len);
static tHCI_TRANSACTION_CB s_transaction_cb = NULL;

/**
 * @brief 初始化hci event处理模块
 * @note 向hci transport层注册各个conn pipe的event回调
 * @return 成功时返回NCI_STATUS_OK
 */
tNCI_STATUS hci_event_dispatcher_init(void) {
    tNCI_STATUS status;
    NFCLOG_D("enter");
    status = hci_transport_register_pipe_event_handler(HCI_DYNAMIC_PIPE_ESE_CONNECTIVITY, hci_event_dispatcher);
    if (NCI_STATUS_OK != status) {
        NFCLOG_E("register hci event handler for ese failed");
    }
    status = hci_transport_register_pipe_event_handler(HCI_DYNAMIC_PIPE_SIM1_CONNECTIVITY, hci_event_dispatcher);
    if (NCI_STATUS_OK != status) {
        NFCLOG_E("register hci event handler for sim1 failed");
    }
    status = hci_transport_register_pipe_event_handler(HCI_DYNAMIC_PIPE_SIM2_CONNECTIVITY, hci_event_dispatcher);
    if (NCI_STATUS_OK != status) {
        NFCLOG_E("register hci event handler for sim2 failed");
    }
    return NCI_STATUS_OK;
}

/**
 * @brief 去初始化hci event处理模块
 * @note 向hci transport层撤销各个conn pipe的event回调
 * @return 成功时返回NCI_STATUS_OK
 */
tNCI_STATUS hci_event_dispatcher_deinit(void) {
    tNCI_STATUS status;
    NFCLOG_D("enter");
    status = hci_transport_register_pipe_event_handler(HCI_DYNAMIC_PIPE_ESE_CONNECTIVITY, NULL);
    if (NCI_STATUS_OK != status) {
        NFCLOG_E("unregister hci event handler for ese failed");
    }
    status = hci_transport_register_pipe_event_handler(HCI_DYNAMIC_PIPE_SIM1_CONNECTIVITY, NULL);
    if (NCI_STATUS_OK != status) {
        NFCLOG_E("unregister hci event handler for sim1 failed");
    }
    status = hci_transport_register_pipe_event_handler(HCI_DYNAMIC_PIPE_SIM2_CONNECTIVITY, NULL);
    if (NCI_STATUS_OK != status) {
        NFCLOG_E("unregister hci event handler for sim2 failed");
    }
    s_transaction_cb = NULL;
    return NCI_STATUS_OK;
}

/**
 * @brief hci event分发
 * @note 解析原始hci event数据，并通知上层
 * @param pipe     event来源pipe
 * @param data     event原始数据
 * @param data_len event数据长度
 */
static void hci_event_dispatcher(uint8_t pipe, const uint8_t *data, uint16_t data_len) {
    const char *src_nfcee_name = NULL;
    switch (pipe) {
    case HCI_DYNAMIC_PIPE_ESE_CONNECTIVITY:
        src_nfcee_name = "eSE1";
        break;
    case HCI_DYNAMIC_PIPE_SIM1_CONNECTIVITY:
        src_nfcee_name = "SIM1";
        break;
    case HCI_DYNAMIC_PIPE_SIM2_CONNECTIVITY:
        src_nfcee_name = "SIM2";
        break;
    default:
        NFCLOG_E("hci event from unkonwn host");
        return;
    }
    uint8_t evt_type = data[0] & HCI_INS_MASK;
    if (HCI_EVT_TRANSACTION != evt_type) {
        // 只处理transaction事件
        NFCLOG_D("drop hci evt type:%02X", evt_type);
        return;
    }
    data++; // byte0是hcp message header，byte1开始才是data
    uint16_t aid_len = 0;
    const uint8_t *aid = NULL;
    if (!find_param_from_bertlv(data, data_len, HCI_EVT_TRANSACTION_AID_TAG, &aid, &aid_len)) {
        NFCLOG_E("invalid hci transaction evt. aid not found");
        return;
    }
    NFCLOG_D("found AID len:%d", aid_len);
    uint16_t param_len = 0;
    const uint8_t *param = NULL;
    if (!find_param_from_bertlv(data, data_len, HCI_EVT_TRANSACTION_PARAM_TAG, &param, &param_len)) {
        NFCLOG_E("invalid hci transaction evt. param not found");
        return;
    }
    NFCLOG_D("found param len:%d", param_len);
    tHCI_TRANSACTION_CB cb = s_transaction_cb;
    if (NULL == cb) {
        NFCLOG_W("no cb for hci event");
        return;
    }
    cb(aid, aid_len, param, param_len, src_nfcee_name);
}

/**
 * @brief 按照bertlv格式解析数据并查找对应tag的内容
 * @param data      原始数据
 * @param data_len  原始数据长度
 * @param tag       要寻找的tag
 * @param param_val 寻找到的tag对应的val指针
 * @param param_len 寻找到的tag的val长度
 * @return 找到对应的合法tag时返回true
 */
static bool find_param_from_bertlv(const uint8_t *data, uint16_t data_len, uint8_t tag, const uint8_t **param_val, uint16_t *param_len) {
    for(int i = 0; i < data_len;) {
        if (data_len < (i + 2)) {
            // 至少有tag+len 2个字节才能组成完整TLV格式
            return false;
        }
        uint8_t curr_tag = data[i];
        uint8_t len_of_len = 1; // len的长度
        uint16_t len = 0;
        if (data[i + 1] < 0x80) {
            // 1-byte长度
            len = data[i + 1];
            if (data_len < (i + 1 + len_of_len + len)) { // i + tag长度1 + len长度1 + len
                NFCLOG_W("invalid ber-tlv format");
                return false;
            }
        } else if (data[i + 1] == 0x80) {
            len_of_len = 3;
            if (data_len < (i + 4)) {
                // 至少有tag + 0x80 + 2-byte
                NFCLOG_W("invalid ber-tlv format");
                return false;
            }
            len = (data[i + 2] << 8) | data[i + 3];
            if (data_len < (i + 1 + len_of_len + len)) { // i + tag长度1 + len长度3 + len
                NFCLOG_W("invalid ber-tlv format");
                return false;
            }
        } else {
            // 更长的长度暂不支持
            NFCLOG_W("len overflow");
            return false;
        }
        if (tag == curr_tag) {
            // 找到正确的tag
            *param_len = len;
            *param_val = data + i + 1 + len_of_len; // tag位置(data[i]) + tag长度1 + len长度
            return true;
        }
        i += 1 + len_of_len + len;
    }
    return false;
}

/**
 * @brief 注册hci event回调，用于往更上层上报hci event
 * @param cb 回调函数指针
 */
void nfa_hci_register_transaction_event_cb(tHCI_TRANSACTION_CB cb) {
    if (NULL != s_transaction_cb) {
        NFCLOG_W("overwrite hci transaction cb");
    }
    s_transaction_cb = cb;
}

#endif // IS_FEATURE_ON(NCI_FEATURE_HCI)
